package com.barryredmond.mileagecalc;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Hashtable;

import javax.microedition.lcdui.Alert;
import javax.microedition.lcdui.AlertType;

import com.barryredmond.rmsfilesystem.FileIOException;
import com.barryredmond.rmsfilesystem.FileSystem;
import com.barryredmond.rmsfilesystem.Serializable;


public class Settings implements Serializable{
    
    private static final String SETTINGS_FILE_NAME = "settings-file";
    
    private static final String TRUE_STRING = "true";
    private static final String FALSE_STRING = "false";
    
    private static Settings SINGLETON;
    
    private Hashtable settings;

    public static Settings getSettings(){
        if(SINGLETON == null){
            SINGLETON = new Settings();
        }
        return SINGLETON;
    }
    
    private Settings(){
        final FileSystem filesystem = FileSystem.getFileSystem();
        if(filesystem.containsFile(SETTINGS_FILE_NAME)){
            try {
                this.unserialize(filesystem.getFile(SETTINGS_FILE_NAME));
            } catch (IOException e) {
                e.printStackTrace();
                showAlert(new Alert("Error", "An Exception was caught while loading the Settings from FileSystem" + e.toString(), null, AlertType.ERROR));
                this.initialize();
            }
        }else{
            this.initialize();
        }
    }
    
    private void initialize(){
        this.settings = new Hashtable();
    }
    
    private boolean getBoolean(String key) throws NullPointerException{
        final String value = (String)settings.get(key);
        if(value.equals(TRUE_STRING)){
            return true;
        }else if(value.equals(FALSE_STRING)){
            return false;
        }else{
            System.out.println("Funny error in getBoolean(" + key + ")");
        }
        throw new NullPointerException("The key " + key + " did exist, but didn't corrospond to a boolean value");
    }
    
    
    public boolean getBoolean(String key, boolean defaultValue){
        try{
            return this.getBoolean(key);
        }catch(NullPointerException e){
        }
        return defaultValue;
    }
    
    public void setBoolean(String key, boolean value){
        this.settings.put(key, value?TRUE_STRING:FALSE_STRING);
        this.saveSettings();
    }
    
    public void setBooleans(String[] keys, boolean[] values){
        if(keys == null || values == null){
            throw new NullPointerException("The keys and values passed to Settigns.setBooleans(String[], boolean[]) can not be null");
        }
        if(keys.length != values.length){
            throw new IllegalArgumentException("The keys and values passed to Settigns.setBooleans(String[], boolean[]) must both be the same length: " + keys.length + " != " + values.length);
        }
        for(int i = 0; i < keys.length; i++){
            this.settings.put(keys[i], values[i]?TRUE_STRING:FALSE_STRING);
        }
        this.saveSettings();
    }
    
    public void saveSettings(){
        Thread t = new Thread(new Runnable(){
            public void run(){
                final FileSystem filesystem = FileSystem.getFileSystem();
                try {
                    filesystem.saveFile(SETTINGS_FILE_NAME, "settings", Settings.this, true);
                } catch (FileIOException e) {
                    showAlert(new Alert("Error", "An Exception was caught while saving the Settings from FileSystem" + e.toString(), null, AlertType.ERROR));
                    e.printStackTrace();
                }
            }
        });
        t.start();
    }

    public void serialize(DataOutputStream dos) throws IOException {
        dos.writeInt(settings.size());
        Enumeration e = settings.keys();
        while(e.hasMoreElements()){
            final String key = (String)e.nextElement();
            final String value = (String)settings.get(key);
            dos.writeUTF(key);
            dos.writeUTF(value);
        }
    }

    public void unserialize(DataInputStream dis) throws IOException {
        int numSettings = dis.readInt();
        this.settings = new Hashtable(numSettings);
        for(int i = 0; i < numSettings; i++){
            final String key = dis.readUTF();
            final String value = dis.readUTF();
            settings.put(key, value);
        }
        
    }
    
    private void showAlert(Alert alert){
        // FIXME: so this is more generic.
        MileageMIDlet.getMileageMIDlet().showAlert(alert);
    }
    
    
}
